package com.dayatang.exam.domain;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;

import com.dayatang.domain.AbstractEntity;
import com.dayatang.domain.QuerySettings;

import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

@Entity
@Table(name = "registrations", uniqueConstraints = @UniqueConstraint(columnNames = {"exam_id", "student", "cancelled"}))
public class Registration extends AbstractEntity {
	
	private static final long serialVersionUID = 2831814546888935472L;

	@ManyToOne
	@JoinColumn(name = "exam_id")
	private Exam exam;
	
	@ManyToOne
	@JoinColumn(name = "student_id")
	private User student;
	
	@Temporal(TemporalType.TIMESTAMP)
	private Date created = new Date();
	
	private boolean cancelled = false;

	public Registration() {
		super();
	}

	public Registration(Exam exam, User student) {
		super();
		this.exam = exam;
		this.student = student;
		this.created = new Date();
		this.cancelled = false;
	}

	public Exam getExam() {
		return exam;
	}

	public void setExam(Exam exam) {
		this.exam = exam;
	}

	public User getStudent() {
		return student;
	}

	public void setStudent(User student) {
		this.student = student;
	}

	public Date getCreated() {
		return created;
	}

	public void setCreated(Date registerTime) {
		this.created = registerTime;
	}

	public boolean isCancelled() {
		return cancelled;
	}

	public void setCancelled(boolean cancelled) {
		this.cancelled = cancelled;
	}
	
	public void cancel() {
		setCancelled(true);
		save();
	}
	
	public static Registration get(Exam exam, User student) {
		return getRepository().getSingleResult(QuerySettings.create(Registration.class)
				.eq("exam", exam)
				.eq("student", student)
				.eq("cancelled", false));
	}
	
	public static boolean exists(Exam exam, User student) {
		List<Registration> registrations = getRepository().find(QuerySettings.create(Registration.class)
				.eq("exam", exam)
				.eq("student", student)
				.eq("cancelled", false));
		return !registrations.isEmpty();
	}

	public static List<Registration> findByExam(Exam exam) {
		return getRepository().find(QuerySettings.create(Registration.class)
				.eq("exam", exam)
				.eq("cancelled", false));
	}

	public static List<Registration> findByStudent(User student) {
		return getRepository().find(QuerySettings.create(Registration.class)
				.eq("student", student)
				.eq("cancelled", false));
	}
	
	public static List<User> findStudentsByExam(Exam exam) {
		List<User> results = new ArrayList<User>();
		for (Registration registration : findByExam(exam)) {
			results.add(registration.getStudent());
		}
		return results;
	}

	public static List<Exam> findExamsByStudent(User student) {
		List<Exam> results = new ArrayList<Exam>();
		for (Registration registration : findByStudent(student)) {
			results.add(registration.getExam());
		}
		return results;
	}
	
	@Override
	public boolean equals(final Object other) {
		if (this == other)
			return true;
		if (!(other instanceof Registration))
			return false;
		Registration castOther = (Registration) other;
		return new EqualsBuilder().append(exam, castOther.exam).append(student,
				castOther.student).append(cancelled, castOther.cancelled)
				.isEquals();
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder(17, 37).append(exam).append(student).append(
				cancelled).toHashCode();
	}

	@Override
	public String toString() {
		return new ToStringBuilder(this).append("exam", exam).append("student",
				student).append("created", created).append(
				"cancelled", cancelled).toString();
	}
}
